/*
    客户端
    IO 多路复用 select
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/select.h>

int main()
{
    char *port = "8888";
    char *ip = "121.37.15.117";
    // socket 函数
    // 创建Socket的通信端点对象（内核）
    // 端点对象的指针信息存放在文件描述符数组
    // 返回给我们一个文件描述符数组下标
    
    // 参数 协议 协议类型 协议0使用默认 
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    
    // 构建目的主机的ip和端口
    struct sockaddr_in sockaddr;
    // 字符串转int，然后 htons 将小端存储转化为大端存储
    sockaddr.sin_port = htons(atoi(port));
    sockaddr.sin_addr.s_addr = inet_addr(ip);
    sockaddr.sin_family = AF_INET;
    // 三次握手
    int ret = connect(socket_fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
    if(ret == -1)
    {
        perror("建立连接失败！");
        exit(1);
    }

    fd_set set;
    while(1)
    {
        // 每次都需要重置监听集合 因为每次返回之后只会剩下准备就绪的
        FD_ZERO(&set);
        // 监听标准输入  和对方通信的socket对象，都是可读
        FD_SET(STDIN_FILENO, &set);
        FD_SET(socket_fd, &set);
        // 参数 最大的文件描述符+1
        select(socket_fd+1, &set, NULL, NULL, NULL);

        // 如果stdin在集合中就说明 stdin准备就绪
        if(FD_ISSET(STDIN_FILENO, &set))
        {
            // 标准输入可读
            char buf[60];
            memset(buf, 0, sizeof(buf));
            read(STDIN_FILENO, buf, sizeof(buf));
            send(socket_fd, buf, sizeof(buf), 0);
        }
        if(FD_ISSET(socket_fd, &set))
        {
            // 和对方通信的socket对象就绪，有数据发过来了
            char buf[60];
            memset(buf, 0, sizeof(buf));
            int size = recv(socket_fd, buf, sizeof(buf), 0);
            if(size == 0)
            {
                printf("对方断开连接\n");
                break;
            }
            printf("buf:%s\n", buf);
        }
    }
    close(socket_fd);
    return 0;
}